home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / Communication / LibraryOfCongress / Source / state.c < prev    next >
C/C++ Source or Header  |  1992-02-06  |  8KB  |  339 lines

  1. /*
  2.  * State machine abstraction.
  3.  * The idea is to keep as much of the hookup dialog
  4.  * as possible in a text file, so that hookup protocols
  5.  * are easy to change here or in other apps.
  6.  * It has grown a few warts.
  7.  *
  8.  * M. J. Hawley
  9.  * mike@media-lab.mit.edu
  10.  * Copyright (c) November 1991, MIT Media Laboratory.
  11.  */
  12.  
  13. extern strlen(), Command(), message(), Put(), Flush(), logout();
  14. extern strcpy(), pgets(), strcmp();
  15. extern char *index(), *rindex();
  16.  
  17. void setState();
  18.  
  19. typedef enum { Plain, Pattern, Status, Goto, FlushS, Pause, CmdS } SType;
  20.  
  21. typedef struct String {
  22.     char *s;
  23.     struct String *next;
  24. } String;
  25.  
  26. typedef struct {
  27.     int type;
  28.     char *name;
  29.     char *first, *last, *label;
  30.     String *l;
  31. } State;
  32.  
  33. #include "util.h"
  34.  
  35. SType lastType = Plain;
  36.  
  37. char *getStr(s,t) char *s, *t; {
  38.     char end = ' ';
  39.  
  40.     *t = '\0';
  41.     s = skipsp(s);
  42.     lastType = Plain;
  43.     switch (*s){
  44.     Case '/': lastType = Pattern;
  45.     Case '+': lastType = Status; s++;
  46.     Case '!': lastType = CmdS; s++;
  47.     Case ',': lastType = FlushS; s++;
  48.     Case '=': lastType = Goto; s = skipsp(s+2);
  49.     }
  50.  
  51.     if (*s=='/' || *s == '"') end = *s++;
  52.     while (*s && !(*s == end || (end==' ' && *s == '\t'))){
  53.         *t = *s++;
  54.         if (*t == '\\') switch (*s){
  55.             Case 'n': *t = '\n'; s++;
  56.             Case 't': *t = '\t'; s++;
  57.             Case 'b': *t = '\b'; s++;
  58.             Default : *t = *s; s++;
  59.         }
  60.         t++;
  61.     }
  62.     *t = '\0';
  63.     if (*s && *s != ' ' && *s != '\t') ++s;
  64.     if (*s) s = skipsp(s);
  65.     return s;
  66. }
  67.  
  68. State *
  69. newState(s) char *s; {
  70.     State *S = Alloc(State);
  71.     S->name = save(s);
  72.     return S;
  73. }
  74.  
  75. String *
  76. addStr(s,t) String *s; char *t; {
  77.     String *start = s, *n = Alloc(String);
  78.     char *p;
  79.     
  80.     p = n->s = save(t);
  81.     if (*p=='/' && (p = index(p+1,'/'))){
  82.         while (p[-1]=='\\') p = index(p+1,'/');
  83.         if (p) *p = '\0';
  84.     }
  85.     
  86.     if (!s) return n;
  87.     while (s->next) s = s->next;
  88.     s->next = n;
  89.     return start;
  90. }
  91.  
  92. void
  93. addString(S,s) State *S; char *s; {
  94.     stripnl(s=skipsp(s));
  95.     S->l = addStr(S->l,s);
  96. }
  97.  
  98. #define MaxS 256
  99. static State *ST[MaxS];
  100. static int NS = 0;
  101.  
  102. void
  103. readState(f) FILE *f; {
  104.     char s[1024], n[1024];
  105.     State *S = (State *)0;
  106.     while (fgets(s,sizeof s,f)){
  107.         stripcomment(s);
  108.         if (blank(s)) continue;
  109.         if (match(s,"[a-zA-Z]*:")){
  110.             sscanf(s,"%[^:]",n);
  111.             S = newState(n);
  112.             ST[NS++] = S;
  113.         } else
  114.         if (S){
  115.             addString(S,s);
  116.         }
  117.     }
  118. }
  119.  
  120. State*
  121. state(s) char *s; {
  122.     int i;
  123.     s = skipsp(s);
  124.     for (i=0;i<NS;i++)
  125.         if (strcmp(s,ST[i]->name)==0) return ST[i];
  126.     return (State *)0;
  127. }
  128.  
  129. char *str(s) char *s; { return s? s : ""; }
  130.  
  131. void
  132. printState(s) State *s; {
  133.     if (!s) printf("huh?\n"); else
  134.     printf("%s: %s %s %s\n",s->name,str(s->first),str(s->last),str(s->label));
  135. }
  136.  
  137. void
  138. ReadState(s) char *s; {
  139.     FILE *f;
  140.     if (!NS){
  141.         f = fopen(s,"r");
  142.         if (f) readState(f), fclose(f);
  143.     }
  144.     setState("Attach");
  145. }
  146.  
  147. State *curState = (State *)0;
  148.  
  149. void
  150. setState(s) char *s; {
  151.     curState = state(s);
  152.     if (strcmp(s,"Detach")==0) logout();
  153.     if (strcmp(s,"Ready")==0) ready();
  154. }
  155.  
  156. void
  157. execute(s) char *s; {
  158.     char t[1024];
  159.  
  160.     if (s[0]=='/') s += strlen(s)+1;
  161.     while ((s=getStr(s,t)) && *t) switch (lastType){
  162.         Case CmdS:    Command(t);
  163.         Case Status : message(t);
  164.         Case Plain  : if (!state(t)) Put("%s",t);
  165.         Case FlushS : Flush(t);
  166.         Case Goto   : setState(t);
  167.     }
  168. }
  169.  
  170. void
  171. execState(s,t) State *s; char *t; {
  172.     String *l;
  173.     if (!s) s = curState;
  174.     if (!s || !s->l) return;
  175.     for (l=s->l; l; l=l->next){
  176.         if (l->s[0]!='/') execute(l->s);
  177.         else
  178.         if (l->s[0]=='/' && *t && match(t,l->s+1)) execute(l->s);
  179.     }
  180. }
  181.  
  182. void
  183. runState(s) char *s; {
  184.     execState(curState,s);
  185. }
  186.  
  187. #define FAILED -1
  188. #define LIST 1
  189. #define LISTA 2
  190. #define ITEM 3
  191.  
  192. int LastItem = 0;
  193. int MoreItems=0;
  194.  
  195. #define MaxItems 10000
  196. typedef struct {
  197.     int n;
  198.     char s[128];
  199. } Item;
  200. Item I[MaxItems];
  201. int NI=0;
  202.  
  203. resetItems(){ NI=0; }
  204.  
  205. char *
  206. skipdigit(s) char *s; { while (isdigit(*s) && *s) ++s; return skipsp(s); }
  207.  
  208. copynl(t,s) char *t, *s; {
  209.     while ((*t = *s) && *t != '\n')
  210.         t++, s++;
  211.     *t = '\0';
  212.     if (*s == '\n') ++s;
  213.     return s;
  214. }
  215.  
  216. addItemList(s) char *s; {
  217.     char t[256];
  218.     int date, numtitles;
  219.     char author[80], title[80];
  220.     char *pt = "                      ";
  221.  
  222.     s = skipsp(s);
  223.     if(LastItem==LIST){ // #  titles  Authors...
  224.       while(*s){
  225.         I[NI].n = atoi(s); s = skipdigit(s);
  226.         numtitles = atoi(s); s = skipdigit(s);
  227.         s = copynl(t,s);
  228.         sprintf(I[NI].s,"%4d %s",numtitles,t);
  229.         NI++;
  230.       }
  231.     } else { // # Auth[22] title date
  232.       while (*s){
  233.         I[NI].n = atoi(s); s = skipdigit(s);
  234.         *title = *author = '\0';
  235.         s = copynl(title,s);
  236.         if (strlen(title)<=22)
  237.             s = copynl(author,s);
  238.         date = atoi(s);  s = skipdigit(s);
  239.         if (*author) sprintf(I[NI].s," %s -- %s [%d]",title,author,date);
  240.         else         sprintf(I[NI].s," %s -- %s [%d]",pt,title,date);
  241.         NI++;
  242.       }
  243.     }
  244.     message("found %d.",NI);
  245. }
  246.  
  247. char *
  248. nthItem(n){
  249.     return n<NI? I[n].s : "";
  250. }
  251.  
  252. nthItemIndex(n){
  253.     return n<NI? I[n].n : 0;
  254. }
  255.  
  256. cleanHighlight(t) char *t; {
  257.     char *p = t;
  258.     if (*p == 27) ++p;
  259.     if (*p == '[' && p[1] == '1' && p[2] == 'm')
  260.         strcpy(t,p+3);
  261. }
  262.  
  263. int MustReload = 0;
  264.  
  265. char *
  266. getReport(buf, reload) char *buf; {
  267.     char *p = buf;
  268.     char t[1024], c;
  269.     int n = 1, More = 3, more=0;
  270.     int flush=0;
  271.     MustReload = reload;
  272.     message("found 0");
  273.     LastItem = 0;
  274.     *p++ = '\n';
  275.   MORE:
  276.     flush=more=0;
  277.     while ((c=pgetc()) && c != '>'){
  278.         t[0] = c; pgetsx(t+1); 
  279.         cleanHighlight(t);
  280.         cleanEsc(t); strcpy(t,skipsp(t));
  281.         if (blank(t) || (t[0]=='n' && t[1]=='\n')) continue;
  282.         if (Verbose) printf("+%s",t);
  283.         if (strindex(t,"Your search:")) continue; else
  284.         if (strindex(t,"Your search for")) flush++, LastItem=FAILED; else
  285.         if (strindex(t,"When searching for")) flush++, LastItem=FAILED; else
  286.         if (strindex(t,"Type of Material:")) LastItem = ITEM; else
  287.         if (strindex(t,"#   titles   ------")) LastItem = LIST; else
  288.         if (strindex(t,"#   --------Author--------  ")) LastItem = LISTA; else
  289.         if (strncmp(t,"LINE",4)==0){
  290.             if (Verbose) printf("++LINE\n");
  291.             LastItem = LIST;
  292.             continue;
  293.         }
  294.         if (t[1]=='=') continue;
  295.         if (strncmp(t,"No more records",14)==0) More=more=0, flush++;
  296.         if (strncmp(t,"#   ",4)==0) continue;
  297.         if (strncmp(t,"----",7)==0) flush++;
  298.         if (strncmp(t,"Enter:",6)==0) flush++;
  299.         if (strncmp(t,"(More)",6)==0) more++, More--, flush++;
  300.         if (strindex(t,"HINTS:")) flush++;
  301.         if (strncmp(t,"Line #",6)==0) flush++;
  302.         if (flush) continue;
  303.  
  304.         if (LastItem == ITEM && strncmp(t,"(Record ",8)==0) continue;
  305.         if (LastItem == ITEM && (!index(t,':') || index(t,':')[-1] ==' ')){
  306.             --p;
  307.             if (*p != ' ') *p++ = ' ';
  308.         }
  309.         strcpy(p,t); p += strlen(p);
  310.     }
  311.     pgetc(); // read the other '>'
  312.     if (more && (More > 0 || LastItem == ITEM)){
  313.         Put("n\r");
  314.         goto MORE;
  315.     }
  316.     if (LastItem == ITEM){
  317.         Put("b\r"); pgets(t);
  318.     }
  319.     MoreItems = more;
  320.     if (LastItem != ITEM) enableMore(MoreItems);
  321.     message("found %d",LastItem==ITEM? 1 : n-1);
  322.     *p = '\0';
  323.  
  324.     if (LastItem != ITEM) addItemList(buf);
  325.     return buf;
  326. }
  327.  
  328. getItem(buf,n) char *buf; {
  329.     char t[256];
  330.     extern reload();
  331.     Put("%d\r",n); pgets(t);
  332.     resetItems();
  333.     getReport(buf,0);
  334.     if (LastItem == ITEM) return 1;
  335.     MustReload = 1;
  336.     DPSAddTimedEntry(1.0,reload,0,10);
  337.     return 0;
  338. }
  339.